// controllers/scoure.go
package controllers

import (
	"fmt"
	"myapi/models"
	"myapi/repositories"
	"myapi/utils"
	"net/http"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
)

// ScoreController 处理成绩相关请求
type ScoreController struct {
	scoreRepo   repositories.ScoreRepository
	userRepo    repositories.UserRepository
	subjectRepo repositories.SubjectRepository
}

// NewScoreController 创建成绩控制器实例
func NewScoreController() *ScoreController {
	return &ScoreController{
		scoreRepo:   repositories.ScoreRepository{},
		userRepo:    repositories.UserRepository{},
		subjectRepo: repositories.SubjectRepository{},
	}
}

// CreateScore 创建新成绩
func (c *ScoreController) CreateScore(ctx *gin.Context) {
	var input struct {
		UserID    uint      `json:"user_id" binding:"required"`
		SubjectID uint      `json:"subject_id" binding:"required"`
		Score     float64   `json:"score" binding:"required"`
		ExamDate  time.Time `json:"exam_date"`
		Remarks   string    `json:"remarks"`
	}
	if err := ctx.ShouldBindJSON(&input); err != nil {
		// 打印详细的绑定错误
		fmt.Printf("绑定JSON错误: %v\n", err)
		fmt.Printf("请求体: %v\n", ctx.Request.Body)
		utils.ErrorResponse(ctx, http.StatusBadRequest, "请求失败: "+err.Error())
		return
	}

	// 检查用户是否存在
	user, err := c.userRepo.FindByID(input.UserID)
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusNotFound, "无效的用户")
		return
	}

	// 检查科目是否存在
	subject, err := c.subjectRepo.FindByID(input.SubjectID)
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusNotFound, "无效的科目id")
		return
	}
	// 查看该人员是否已经存在成绩
	existingScore, err := c.scoreRepo.FindByUserIDAndSubjectID(user.ID, subject.ID)
	if err == nil && existingScore != nil {
		// 找到了成绩，说明已经存在
		utils.ErrorResponse(ctx, http.StatusConflict, "该人员已经存在成绩")
		return
	}
	// 创建成绩记录
	score := models.Score{
		UserID:    user.ID,
		SubjectID: subject.ID,
		Score:     input.Score,
		ExamDate:  input.ExamDate,
		Remarks:   input.Remarks,
	}

	if err := c.scoreRepo.Create(&score); err != nil {
		utils.ErrorResponse(ctx, http.StatusInternalServerError, "成绩创建失败"+err.Error())
		return
	}

	// 重新获取成绩记录以包含关联数据
	createdScore, err := c.scoreRepo.FindByID(score.ID)
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusInternalServerError, "成绩再次创建失败")
		return
	}

	utils.SuccessResponse(ctx, createdScore.ToResponse(), "成绩创建成功")
}

// GetScore 获取单个成绩
func (c *ScoreController) GetScore(ctx *gin.Context) {
	idStr := ctx.Param("id")
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusBadRequest, "无效的成绩id")
		return
	}

	score, err := c.scoreRepo.FindByID(uint(id))
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusNotFound, "成绩不存在")
		return
	}
	utils.SuccessResponse(ctx, score.ToResponse(), "成绩获取成功")
}

// GetScores 获取所有成绩
func (c *ScoreController) GetScores(ctx *gin.Context) {
	pageStr := ctx.DefaultQuery("page", "1")
	pageSizeStr := ctx.DefaultQuery("page_size", "10")
	userIDStr := ctx.Query("user_id")
	subjectIDStr := ctx.Query("subject_id")

	page, _ := strconv.Atoi(pageStr)
	pageSize, _ := strconv.Atoi(pageSizeStr)

	if page < 1 {
		page = 1
	}
	if pageSize < 1 || pageSize > 100 {
		pageSize = 10
	}

	var scores []models.Score
	var count int64
	var err error

	// 根据筛选条件获取成绩
	if userIDStr != "" {
		userID, _ := strconv.ParseUint(userIDStr, 10, 64)
		scores, count, err = c.scoreRepo.FindByUserID(uint(userID), page, pageSize)
	} else if subjectIDStr != "" {
		subjectID, _ := strconv.ParseUint(subjectIDStr, 10, 64)
		scores, count, err = c.scoreRepo.FindBySubjectID(uint(subjectID), page, pageSize)
	} else {
		scores, count, err = c.scoreRepo.FindAll(page, pageSize)
	}

	if err != nil {
		utils.ErrorResponse(ctx, http.StatusInternalServerError, "成绩获取失败"+err.Error())
		return
	}

	// 转换为响应格式
	var scoreResponses []models.ScoreResponse
	for _, score := range scores {
		scoreResponses = append(scoreResponses, score.ToResponse())
	}

	data := gin.H{
		"scores":     scoreResponses,
		"total":      count,
		"page":       page,
		"page_size":  pageSize,
		"total_page": (count + int64(pageSize) - 1) / int64(pageSize),
	}

	utils.SuccessResponse(ctx, data, "成绩查找成功")
}

// UpdateScore 更新成绩
func (c *ScoreController) UpdateScore(ctx *gin.Context) {
	idStr := ctx.Param("id")
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusBadRequest, "无效的成绩id"+err.Error())
		return
	}

	score, err := c.scoreRepo.FindByID(uint(id))
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusNotFound, "无效的成绩id")
		return
	}

	var input struct {
		UserID    uint      `json:"user_id"`
		SubjectID uint      `json:"subject_id"`
		Score     float64   `json:"score"`
		ExamDate  time.Time `json:"exam_date"`
		Remarks   string    `json:"remarks"`
	}

	if err := ctx.ShouldBindJSON(&input); err != nil {
		utils.ErrorResponse(ctx, http.StatusBadRequest, "Invalid request data")
		return
	}

	// 更新字段
	if input.UserID != 0 {
		// 检查用户是否存在
		_, err := c.userRepo.FindByID(input.UserID)
		if err != nil {
			utils.ErrorResponse(ctx, http.StatusNotFound, "User not found")
			return
		}
		score.UserID = input.UserID
	}

	if input.SubjectID != 0 {
		// 检查科目是否存在
		_, err := c.subjectRepo.FindByID(input.SubjectID)
		if err != nil {
			utils.ErrorResponse(ctx, http.StatusNotFound, "Subject not found")
			return
		}
		score.SubjectID = input.SubjectID
	}

	if input.Score != 0 {
		score.Score = input.Score
	}

	if !input.ExamDate.IsZero() {
		score.ExamDate = input.ExamDate
	}

	if input.Remarks != "" {
		score.Remarks = input.Remarks
	}

	if err := c.scoreRepo.Update(score); err != nil {
		utils.ErrorResponse(ctx, http.StatusInternalServerError, "Failed to update score")
		return
	}

	// 重新获取成绩记录以包含关联数据
	updatedScore, err := c.scoreRepo.FindByID(score.ID)
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusInternalServerError, "Failed to retrieve updated score")
		return
	}

	utils.SuccessResponse(ctx, updatedScore.ToResponse(), "Score updated successfully")
}

// DeleteScore 删除成绩
func (c *ScoreController) DeleteScore(ctx *gin.Context) {
	idStr := ctx.Param("id")
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusBadRequest, "找不到成绩id")
		return
	}

	if err := c.scoreRepo.Delete(uint(id)); err != nil {
		utils.ErrorResponse(ctx, http.StatusInternalServerError, "删除失败,请检查数据完整性")
		return
	}
	utils.SuccessResponse(ctx, nil, "成绩删除成功")
}

func (c *ScoreController) GetTopThreeScores(ctx *gin.Context) {
	subjectIDStr := ctx.Query("subject_id")
	subjectID, _ := strconv.ParseUint(subjectIDStr, 10, 64)

	scores, err := c.scoreRepo.FindTopThreeScores(uint(subjectID))
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusInternalServerError, "无法查出"+err.Error())
		return
	}

	// 创建一个切片来存储带有额外字段的成绩信息
	var scoreResponses []map[string]interface{}

	for _, score := range scores {
		user, err := c.userRepo.FindByID(score.UserID)
		if err != nil {
			utils.ErrorResponse(ctx, http.StatusInternalServerError, "无法查出"+err.Error())
			return
		}
		subject, err := c.subjectRepo.FindByID(score.SubjectID)
		if err != nil {
			utils.ErrorResponse(ctx, http.StatusInternalServerError, "无法查出"+err.Error())
			return
		}

		// 构建响应对象
		response := map[string]interface{}{
			"id":           score.ID,
			"user_id":      score.UserID,
			"subject_id":   score.SubjectID,
			"score":        score.Score,
			"created_at":   score.CreatedAt,
			"updated_at":   score.UpdatedAt,
			"user_name":    user.Name,
			"subject_name": subject.Name,
		}

		// 将响应对象添加到切片中
		scoreResponses = append(scoreResponses, response)
	}

	utils.SuccessResponse(ctx, scoreResponses, "前三位成绩已出")
}

// 查找单科目最低分
func (c *ScoreController) GetLowestScore(ctx *gin.Context) {
	subjectIDStr := ctx.Query("subject_id")
	subjectID, _ := strconv.ParseUint(subjectIDStr, 10, 64)
	score, err := c.scoreRepo.FindLowestScore(uint(subjectID))
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusInternalServerError, "无法查出"+err.Error())
		return
	}
	user, err := c.userRepo.FindByID(score.UserID)
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusInternalServerError, "无法查出"+err.Error())
		return
	}
	subject, err := c.subjectRepo.FindByID(score.SubjectID)
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusInternalServerError, "无法查出"+err.Error())
		return
	}
	response := map[string]interface{}{
		"id":           score.ID,
		"user_id":      score.UserID,
		"subject_id":   score.SubjectID,
		"score":        score.Score,
		"created_at":   score.CreatedAt,
		"updated_at":   score.UpdatedAt,
		"user_name":    user.Name,
		"subject_name": subject.Name,
	}
	utils.SuccessResponse(ctx, response, "最低分已出")
}
